﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using WarsKeyChanger.Properties;
using System.Diagnostics;
using System.Reflection;



namespace WarsKeyChanger
{

    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();

        }

        protected void SaveConfig()
        {
            List<string> errStringList = new List<string>();

            foreach (var x in dictHotKeys)
            {
                try
                {
                    StockHotKeyConfig[x.Key] = x.Value.KeyCode;
                }
                catch (Exception ex)
                {
                    errStringList.Add(ex.Message);
                }
            }

            try
            {
                BloodConfig.IsShowEnemyBlood = this.chkIsShowEnemyBlood.Checked;
            }
            catch (Exception ex)
            {
                errStringList.Add(ex.Message);
            }

            try
            {
                BloodConfig.IsShowSeftBlood = this.chkIsShowSelfBlood.Checked;
            }
            catch (Exception ex)
            {
                errStringList.Add(ex.Message);
            }


            if (errStringList.Count > 0)
            {
                MessageBox.Show("保存配置失败");
            }
        }


        private string formClass = null;
        private string formTitle = "Warcraft III";

        private IntPtr warcraftWindowHandle = System.IntPtr.Zero;
        private bool isWarWndHandleChanged = false;
        /// <summary>
        /// war III 的窗口句柄
        /// </summary>
        protected IntPtr WarcraftWindowHandle
        {
            get
            {
                isWarWndHandleChanged = false;
                var newWarcraftWindowHandle = Belyn.Common.API.WinAPI.FindWindowEx(new HandleRef(this, IntPtr.Zero), new HandleRef(this, IntPtr.Zero), formClass, formTitle);
                if (newWarcraftWindowHandle != warcraftWindowHandle)
                {
                    isWarWndHandleChanged = true;
                    WarcraftWindowHandle_Changed(warcraftWindowHandle, newWarcraftWindowHandle);
                    warcraftWindowHandle = newWarcraftWindowHandle;
                }

                return warcraftWindowHandle;
            }

            private set
            {
                warcraftWindowHandle = value;
            }

        }

        public static Dictionary<Keys, KeysHotValue> dictHotKeys = new Dictionary<Keys, KeysHotValue>();

        BloodConfig BloodConfig;
        StockConfig StockHotKeyConfig;
        Belyn.Common.API.GlobalKeyHook GlobalKeyHooker; 

        private void Form1_Load(object sender, EventArgs e)
        {
            GlobalKeyHooker = new Belyn.Common.API.GlobalKeyHook();
            GlobalKeyHooker.OnKeyUpHook += GlobalKeyHooker_OnKeyUpHook; 
             

            BloodConfig = new WarsKeyChanger.BloodConfig(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WarsKeyChangerConfig.ini"));
            this.chkIsShowEnemyBlood.Checked = BloodConfig.IsShowEnemyBlood;
            this.chkIsShowSelfBlood.Checked = BloodConfig.IsShowSeftBlood;


            StockHotKeyConfig = new StockConfig(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WarsKeyChangerConfig.ini"));

            dictHotKeys.Add(Keys.NumPad1, new KeysHotValue(StockHotKeyConfig.NumPad1HotKey, 100001, '1'));
            dictHotKeys.Add(Keys.NumPad2, new KeysHotValue(StockHotKeyConfig.NumPad2HotKey, 100002, '2'));

            dictHotKeys.Add(Keys.NumPad4, new KeysHotValue(StockHotKeyConfig.NumPad4HotKey, 100004, '4'));
            dictHotKeys.Add(Keys.NumPad5, new KeysHotValue(StockHotKeyConfig.NumPad5HotKey, 100005, '5'));

            dictHotKeys.Add(Keys.NumPad7, new KeysHotValue(StockHotKeyConfig.NumPad7HotKey, 100007, '7'));
            dictHotKeys.Add(Keys.NumPad8, new KeysHotValue(StockHotKeyConfig.NumPad8HotKey, 100008, '8'));

            this.txt1.Text = ((StockHotKeyConfig.NumPad1HotKey)).ToString();
            this.txt2.Text = ((StockHotKeyConfig.NumPad2HotKey)).ToString();

            this.txt4.Text = ((StockHotKeyConfig.NumPad4HotKey)).ToString();
            this.txt5.Text = ((StockHotKeyConfig.NumPad5HotKey)).ToString();

            this.txt7.Text = ((StockHotKeyConfig.NumPad7HotKey)).ToString();
            this.txt8.Text = ((StockHotKeyConfig.NumPad8HotKey)).ToString();

            //btnApply_Click(null, null);

            this.txt1.KeyUp += txt1_KeyUp;
            this.txt2.KeyUp += txt2_KeyUp;


            this.txt4.KeyUp += txt4_KeyUp;
            this.txt5.KeyUp += txt5_KeyUp;


            this.txt7.KeyUp += txt7_KeyUp;
            this.txt8.KeyUp += txt8_KeyUp;

            //this.Controls.OfType<Control>().ToList().ForEach(x => { x.Enabled = false; });
        }


        private void btnApply_Click(object sender, EventArgs e)
        {
            //foreach (var x in dictHotKeys)
            //{
            //    RegisterHotKey(this.Handle, x.Value.HotValue, 0, (UInt32)x.Value.KeyCode);

            //} 
            SaveConfig();
        }

        void txt1_KeyUp(object sender, KeyEventArgs e)
        {
            ((TextBox)sender).Text = (e.KeyCode).ToString();
            dictHotKeys[Keys.NumPad1].KeyCode = e.KeyCode;
        }
        void txt2_KeyUp(object sender, KeyEventArgs e)
        {
            ((TextBox)sender).Text = (e.KeyCode).ToString();
            dictHotKeys[Keys.NumPad2].KeyCode = e.KeyCode;
        }

        void txt4_KeyUp(object sender, KeyEventArgs e)
        {
            ((TextBox)sender).Text = (e.KeyCode).ToString();
            dictHotKeys[Keys.NumPad4].KeyCode = e.KeyCode;
        }
        void txt5_KeyUp(object sender, KeyEventArgs e)
        {
            ((TextBox)sender).Text = (e.KeyCode).ToString();
            dictHotKeys[Keys.NumPad5].KeyCode = e.KeyCode;
        }

        void txt7_KeyUp(object sender, KeyEventArgs e)
        {
            ((TextBox)sender).Text = (e.KeyCode).ToString();
            dictHotKeys[Keys.NumPad7].KeyCode = e.KeyCode;
        }
        void txt8_KeyUp(object sender, KeyEventArgs e)
        {
            ((TextBox)sender).Text = (e.KeyCode).ToString();
            dictHotKeys[Keys.NumPad8].KeyCode = e.KeyCode;
        }

        private const int KEY_QUOTLEFT = 219;//键盘上 [ 键的代码  
        private const int KEY_QUOTRIGHT = 221;//键盘上 ] 键的代码
        /// <summary>
        /// 是否开启
        /// </summary>
        protected bool IsHookEnable
        {
            get
            {
                return this.btnSwith.Text == "停用";
            }
        }
        private void btnSwith_Click(object sender, EventArgs e)
        {
            if (this.btnSwith.Text == "开启")
            {
                GlobalKeyHooker.StartHook(); 
                this.btnSwith.Text = "停用";
            }
            else if (this.btnSwith.Text == "停用")
            {
                GlobalKeyHooker.StopHook(); 
                WarcraftWindowHandle = IntPtr.Zero;
                this.btnSwith.Text = "开启";
            }
            BloodHook();
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            btnSwith_Click(null, null);
            base.OnFormClosing(e);
        }


        protected void GlobalKeyHooker_OnKeyUpHook(object sender, Belyn.Common.API.GlobalKeyHookEventAgrs e)
        {

            if (e.KeyParam.flags > 0)
            {
                dictHotKeys.Where(x => (int)x.Value.KeyCode == e.KeyCode).ToList().ForEach(x =>
                {
                    var hwnd = this.WarcraftWindowHandle;
                    if (hwnd != IntPtr.Zero)
                    {
                        this.label7.Text = string.Format("war键盘钩子：{0}->{1}", x.Value.KeyCode.ToString(), x.Key.ToString());
                        Dictionary<string, string> messageList = new Dictionary<string, string>();
                        messageList.Add("e.KeyParam.dwExtraInfo", e.KeyParam.dwExtraInfo + "");
                        messageList.Add("e.KeyParam.flags", e.KeyParam.flags + "");
                        messageList.Add("e.KeyParam.scanCode", e.KeyParam.scanCode + "");
                        messageList.Add("e.KeyParam.time", e.KeyParam.time + "");
                        messageList.Add("e.KeyParam.vkCode", e.KeyParam.vkCode + "");
                        this.label7.Text += "\r\n" + string.Join("\r\n", messageList.Select(y => string.Format("{0}:{1}", y.Key, y.Value)).ToArray());

                        Belyn.Common.API.WinAPI.SendMessage(hwnd, Belyn.Common.API.WinAPI.WM_KEYDOWN, (int)x.Key, IntPtr.Zero);
                        Belyn.Common.API.WinAPI.SendMessage(hwnd, Belyn.Common.API.WinAPI.WM_KEYUP, (int)x.Key, IntPtr.Zero);

                    }

                });
            }
        }
         

        protected void BloodHook()
        {
            var hwnd = this.WarcraftWindowHandle;

            if (isWarWndHandleChanged) return;

            if (IsHookEnable)
            {
                if (hwnd != IntPtr.Zero)
                {
                    Belyn.Common.API.WinAPI.SetForegroundWindow(hwnd);
                    if (this.chkIsShowEnemyBlood.Checked)
                    {

                        Belyn.Common.API.WinAPI.keybd_event(KEY_QUOTRIGHT, 0, 0, 0);
                        //Belyn.Common.API.WinAPI.SendMessage(hwnd, Belyn.Common.API.WinAPI.WM_KEYDOWN, KEY_QUOTRIGHT, IntPtr.Zero);
                    }
                    else
                    {
                        Belyn.Common.API.WinAPI.SendMessage(hwnd, Belyn.Common.API.WinAPI.WM_KEYUP, KEY_QUOTRIGHT, IntPtr.Zero);
                    }

                    if (this.chkIsShowSelfBlood.Checked)
                    {
                        Belyn.Common.API.WinAPI.keybd_event(KEY_QUOTLEFT, 0, 0, 0);
                        //Belyn.Common.API.WinAPI.SendMessage(hwnd, Belyn.Common.API.WinAPI.WM_KEYDOWN, KEY_QUOTLEFT, IntPtr.Zero);
                    }
                    else
                    {
                        Belyn.Common.API.WinAPI.SendMessage(hwnd, Belyn.Common.API.WinAPI.WM_KEYUP, KEY_QUOTLEFT, IntPtr.Zero);
                    }
                }
            }
            else
            {
                if (hwnd != IntPtr.Zero)
                {
                    Belyn.Common.API.WinAPI.SendMessage(hwnd, Belyn.Common.API.WinAPI.WM_KEYUP, KEY_QUOTRIGHT, IntPtr.Zero);
                    Belyn.Common.API.WinAPI.SendMessage(hwnd, Belyn.Common.API.WinAPI.WM_KEYUP, KEY_QUOTLEFT, IntPtr.Zero);
                }
            }

        }


        private void chkIsShowEnemyBlood_CheckedChanged(object sender, EventArgs e)
        {
            BloodHook();
        }

        private void chkIsShowSelfBlood_CheckedChanged(object sender, EventArgs e)
        {
            BloodHook();
        }

        private void WarcraftWindowHandle_Changed(IntPtr oldWarWndHandle, IntPtr newWarWndHandle)
        {
            if (oldWarWndHandle != IntPtr.Zero)
            {
                Belyn.Common.API.WinAPI.SendMessage(oldWarWndHandle, Belyn.Common.API.WinAPI.WM_KEYUP, KEY_QUOTRIGHT, IntPtr.Zero);
                Belyn.Common.API.WinAPI.SendMessage(oldWarWndHandle, Belyn.Common.API.WinAPI.WM_KEYUP, KEY_QUOTLEFT, IntPtr.Zero);
            }

            var hwnd = newWarWndHandle;
            if (IsHookEnable)
            {
                if (hwnd != IntPtr.Zero)
                {
                    Belyn.Common.API.WinAPI.SetForegroundWindow(hwnd);
                    if (this.chkIsShowEnemyBlood.Checked)
                    {
                        Belyn.Common.API.WinAPI.keybd_event(KEY_QUOTRIGHT, 0, 0, 0);
                        //Belyn.Common.API.WinAPI.SendMessage(hwnd, Belyn.Common.API.WinAPI.WM_KEYDOWN, KEY_QUOTRIGHT, IntPtr.Zero);
                    }

                    if (this.chkIsShowSelfBlood.Checked)
                    {
                        Belyn.Common.API.WinAPI.keybd_event(KEY_QUOTLEFT, 0, 0, 0);
                        //Belyn.Common.API.WinAPI.SendMessage(hwnd, Belyn.Common.API.WinAPI.WM_KEYDOWN, KEY_QUOTLEFT, IntPtr.Zero);
                    }
                }
            }
        } 

    }

    public class KeysHotValue
    {
        public KeysHotValue(Keys keyCode, UInt32 hotValue, char keyValue)
        {
            KeyCode = keyCode;
            HotValue = hotValue;
            KeyValue = keyValue;
        }
        public Keys KeyCode { get; set; }
        public UInt32 HotValue { get; protected set; }
        public char KeyValue { get; set; }
    }

    public class SoftHelper
    {




        private const int SW_SHOWNOMAL = 1;
        private static void HandleRunningInstance(Process instance)
        {
            Belyn.Common.API.WinAPI.ShowWindowAsync(instance.MainWindowHandle, SW_SHOWNOMAL);//显示
            Belyn.Common.API.WinAPI.SetForegroundWindow(instance.MainWindowHandle);//当到最前端
        }

        private static Process RuningInstance()
        {
            Process currentProcess = Process.GetCurrentProcess();
            Process[] Processes = Process.GetProcessesByName(currentProcess.ProcessName);

            foreach (Process process in Processes)
            {
                if (process.Id != currentProcess.Id)
                {
                    return process;
                }
            }


            return null;
        }

        /// <summary>
        /// 程序以单例运行 
        /// </summary>
        public static void SoftSingle<T>() where T : Form, new()
        {
            Process process = RuningInstance();
            if (process == null)
            {
                var mainForm = new T();
                Application.Run(mainForm);
            }
            else
            {
                HandleRunningInstance(process);
            }
        }


    }
}
